#ifndef AEA2D33B_833A_4D94_ABDF_D6FB20BABD1A
#define AEA2D33B_833A_4D94_ABDF_D6FB20BABD1A

// 线程池
#include <iostream>
#include <queue>

#include "Task.hpp"


#define NUM 10

class ThreadPool
{
private:
    int num;    // 要设置的线程的数量
    bool stop;  // 是否开始
    std::queue<Task> task_queue;    // 任务队列

    pthread_mutex_t lock;   // 加锁
    pthread_cond_t cond;    // 环境变量

    // 设计成为单例模式
    static ThreadPool* sInst_;
private:
    ThreadPool(int num_ = NUM)
        :num(num_)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
    }
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool operator()(const ThreadPool&) = delete;
    ~ThreadPool()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
private:
    // 小功能：判断任务队列是否为空 && 加锁 && 解锁 && 线程等待 && 
    //         线程唤醒 && 线程要执行的代码 && 初始化线程池
    // 1.判断任务队列是否为空
    bool queueIsEmpty() { return task_queue.empty(); }
    // 2. 加锁
    void Lock() { pthread_mutex_lock(&lock); }
    // 3. 解锁
    void unLock() { pthread_mutex_unlock(&lock); }
    // 4. 线程等待
    void threadWait() { pthread_cond_wait(&cond, &lock); }
    // 5. 线程唤醒
    void threadWakeUp() { pthread_cond_signal(&cond); }
    // 6. 线程要执行的代码
    static void* threadRoutinue(void* args)
    {
        ThreadPool* tp = static_cast<ThreadPool*>(args);
        while (true)
        {
            Task t;
            tp->Lock();
            while(tp->queueIsEmpty()){
                // 没有任务存在，让线程等待
                tp->threadWait();
            }
            // 开始有任务到来哦
            tp->popTask(t);     // 将任务从任务队列中移出来(目的：执行这个任务)
            tp->unLock();
            t.ProcessOn();
        }
        
    }
    // 7.初始化线程池
    bool initThreadPool()
    {
        for(int i = 0; i < num; i++)
        {
            pthread_t tid;
            if(pthread_create(&tid, nullptr, threadRoutinue, this) != 0){
                lg(FATAL, "create thread pool error");
                return false;
            }
        }
        lg(INFO, "create thread pool success");
        return true;
    }
public:
    // 对外接口：设置一个类调用接口(设置线程池为单例模式) && 将准备执行的任务放入任务队列 && 将马上要执行的任务从任务队列中放出
    // 1.设置一个类调用接口(设置线程池为单例模式)
    static ThreadPool* getInstance()
    {
        static pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER;
        if(sInst_ == nullptr)
        {
            pthread_mutex_lock(&mutex_);
            if(sInst_ == nullptr)
            {
                sInst_ = new ThreadPool();
                sInst_->initThreadPool();
            }
        }
        return sInst_;
    }
    // 2.将要执行的任务放入任务队列
    void pushTask(const Task& task)
    {
        Lock();
        task_queue.push(task);
        unLock();
        threadWakeUp();
    }
    // 3. 将马上要执行的任务从任务队列中放出
    void popTask(Task& task)    // 输出型参数
    {
        task = task_queue.front();
        task_queue.pop();
    }
};

ThreadPool* ThreadPool::sInst_ = nullptr;


#endif /* AEA2D33B_833A_4D94_ABDF_D6FB20BABD1A */
